package main

/*
	下一个排列
实现获取 下一个排列 的函数，算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列，则将数字重新排列成最小的排列（即升序排列）。
必须 原地 修改，只允许使用额外常数空间。

示例 1：
输入：nums = [1,2,3]
输出：[1,3,2]

示例 2：
输入：nums = [3,2,1]
输出：[1,2,3]
 */

/*
我们希望下一个数比当前数大，这样才满足“下一个排列”的定义。
因此只需要将后面的「大数」与前面的「小数」交换，就能得到一个更大的数。
比如 123456，将 5 和 6 交换就能得到一个更大的数 123465。
我们还希望下一个数增加的幅度尽可能的小，这样才满足“下一个排列与当前排列紧邻“的要求。
为了满足这个要求，我们需要：
	  在尽可能靠右的低位进行交换，需要从后向前查找
	将一个 尽可能小的「大数」 与前面的「小数」交换。
	  比如 123465，下一个排列应该把 5 和 4 交换而不是把 6 和 4 交换
	将「大数」换到前面后，需要将「大数」后面的所有数重置为升序，
	  升序排列就是最小的排列。以 123465 为例：首先按照上一步，交换 5 和 4，
	得到 123564；然后需要将 5 之后的数重置为升序，得到 123546。
	显然 123546 比 123564 更小，123546 就是 123465 的下一个排列

 */

func nextPermutation(nums []int) {
	// 以 1258463 为例
	length := len(nums)
	if length < 2 {
		return
	}
	i, j := length-2, length-1
	// 从后向前扫描[0:length] 找到第一个nums[i] < nums[i + 1] 的数
	for i >= 0 && nums[i] >= nums[i + 1] {
		i --
	}
	// 从后向前扫描[i:length] 找到第一个 nums[j] > nums[i]
	if i >= 0 {
		for j >= 0 && nums[i] >= nums[j] {
			j --
		}
		nums[i], nums[j] = nums[j], nums[i]
	}

	// 翻转[i + 1:length]
	left, right := i + 1, length - 1
	for left < right {
		nums[left], nums[right] = nums[right], nums[left]
		left ++
		right --
	}
	//fmt.Println(nums)
}

func main() {
	nextPermutation([]int{3,2,1})
}
